using System.Security.Cryptography;

public class Decryptor
{
    const int BUFFER_SIZE = 4096 * 1024; //4MB缓存

    private readonly string method;
    private readonly byte[] key;
    private readonly byte[] iv = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];

    /// <summary>
    /// 从xKey中提取key、iv等相关参数
    /// </summary>
    /// <param name="xKey">在m3n8中取出的文本行，如：#EXT-X-KEY:METHOD=AES-128,URI="enc.key",IV=0x00000000000000000000000000000000</param>
    public Decryptor(string xKey, Uri BaseUri)
    {
        foreach (var s in xKey.Split(","))
        {
            var pairs = s.Split("=");
            if (pairs[0].Equals("METHOD", StringComparison.CurrentCultureIgnoreCase))
            {
                method = pairs[1].ToUpper();
                if (method != "AES-128")
                    throw new Exception("不受支持的加密算法：" + method);
            }
            else if (pairs[0].Equals("URI", StringComparison.CurrentCultureIgnoreCase))
            {
                string url = pairs[1][1..^1];//去掉"
                if (!Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out Uri uri))
                    throw new Exception("URI无效：" + pairs[1]);

                if (!uri.IsAbsoluteUri)
                {
                    // 处理相对路径
                    if (url.StartsWith('/'))
                    {
                        // 绝对路径
                        var domain = new Uri(BaseUri.GetLeftPart(UriPartial.Authority));
                        uri = new Uri(domain, uri);
                    }
                    else
                    {
                        // 相对路径
                        uri = new Uri(BaseUri, uri);
                    }
                }

                //载入key
                using var httpClient = new HttpClient();
                using var response = httpClient.GetAsync(uri).Result;
                using var stream = response.Content.ReadAsStreamAsync().Result;
                key = new byte[stream.Length];
                stream.Read(key, 0, key.Length);
                stream.Close();
            }
            else if (pairs[0].Equals("IV", StringComparison.CurrentCultureIgnoreCase))
            {
                iv = Convert.FromHexString(pairs[1].AsSpan(2));//带0x前缀
            }
        }
    }

    //aes对象，只需创建一次
    private Aes? aes = null;

    /// <summary>
    /// 对input内容执行aes128解密，解密内容写入到output的文件
    /// </summary>
    /// <param name="input">待解密内容</param>
    /// <param name="output">解密得到的内容存储路径</param>
    public void AES128(byte[] input, string output)
	{
        //创建aes对象
        if (null == aes)
        {
            aes = Aes.Create();

            aes.Key = key;
            aes.IV = iv;
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;
        }

        //执行解密操作
        using var source = new MemoryStream(input, false);
        using var outfile = new FileStream(output, FileMode.Create, FileAccess.Write);
        using ICryptoTransform decryptor = aes.CreateDecryptor();
        using var cs = new CryptoStream(source, decryptor, CryptoStreamMode.Read);
        cs.CopyTo(outfile, BUFFER_SIZE);
    }
}
